package com.cencat.common.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cencat.common.dto.BaseDTO;
import com.cencat.common.entity.BaseEntity;
import com.cencat.common.enums.ErrorCode;
import com.cencat.common.exception.BusinessException;
import com.cencat.common.response.ApiResponse;
import com.cencat.common.response.PageResponse;
import com.cencat.common.service.BaseService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 基础控制器
 * 提供通用的REST API方法
 * 
 * @param <S> 服务类型
 * @param <T> 实体类型
 * @param <D> DTO类型
 * @author cencat
 * @since 2024-01-01
 */
@Tag(name = "基础API", description = "提供通用的CRUD操作")
public abstract class BaseController<S extends BaseService<T>, T extends BaseEntity, D extends BaseDTO> {

    private static final Logger log = LoggerFactory.getLogger(BaseController.class);

    @Autowired
    protected S baseService;

    /**
     * 创建实体
     * 
     * @param dto 创建DTO
     * @return 创建结果
     */
    @PostMapping
    @Operation(summary = "创建实体", description = "创建新的实体对象")
    public ApiResponse<Boolean> create(@Valid @RequestBody D dto) {
        try {
            T entity = convertToEntity(dto);
            boolean result = baseService.save(entity);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("创建实体失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        } catch (Exception e) {
            log.error("创建实体异常: {}", e.getMessage(), e);
            return ApiResponse.error(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 根据ID删除实体
     * 
     * @param id 主键ID
     * @return 删除结果
     */
    @DeleteMapping("/{id}")
    @Operation(summary = "删除实体", description = "根据ID删除实体")
    public ApiResponse<Boolean> deleteById(
            @Parameter(description = "主键ID", required = true) @PathVariable Long id) {
        try {
            boolean result = baseService.removeById(id);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("删除实体失败: id={}, error={}", id, e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        } catch (Exception e) {
            log.error("删除实体异常: id={}, error={}", id, e.getMessage(), e);
            return ApiResponse.error(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 批量删除实体
     * 
     * @param ids ID列表
     * @return 删除结果
     */
    @DeleteMapping("/batch")
    @Operation(summary = "批量删除实体", description = "根据ID列表批量删除实体")
    public ApiResponse<Boolean> deleteBatch(
            @Parameter(description = "ID列表", required = true) @RequestBody List<Long> ids) {
        try {
            boolean result = baseService.removeByIds(ids);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("批量删除实体失败: ids={}, error={}", ids, e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        } catch (Exception e) {
            log.error("批量删除实体异常: ids={}, error={}", ids, e.getMessage(), e);
            return ApiResponse.error(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 更新实体
     * 
     * @param id 主键ID
     * @param dto 更新DTO
     * @return 更新结果
     */
    @PutMapping("/{id}")
    @Operation(summary = "更新实体", description = "根据ID更新实体")
    public ApiResponse<Boolean> updateById(
            @Parameter(description = "主键ID", required = true) @PathVariable Long id,
            @Valid @RequestBody D dto) {
        try {
            T entity = convertToEntity(dto);
            entity.setId(id);
            boolean result = baseService.updateById(entity);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("更新实体失败: id={}, error={}", id, e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        } catch (Exception e) {
            log.error("更新实体异常: id={}, error={}", id, e.getMessage(), e);
            return ApiResponse.error(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 根据ID查询实体
     * 
     * @param id 主键ID
     * @return 实体信息
     */
    @GetMapping("/{id}")
    @Operation(summary = "查询实体", description = "根据ID查询实体详情")
    public ApiResponse<T> getById(
            @Parameter(description = "主键ID", required = true) @PathVariable Long id) {
        try {
            T entity = baseService.getById(id);
            if (entity == null) {
                return ApiResponse.error(ErrorCode.DATA_NOT_FOUND);
            }
            return ApiResponse.success(entity);
        } catch (Exception e) {
            log.error("查询实体异常: id={}, error={}", id, e.getMessage(), e);
            return ApiResponse.error(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 分页查询实体列表
     * 
     * @param dto 查询DTO
     * @return 分页结果
     */
    @GetMapping("/page")
    @Operation(summary = "分页查询", description = "分页查询实体列表")
    public ApiResponse<PageResponse<T>> page(@Valid D dto) {
        try {
            Page<T> page = new Page<>(dto.getPageNum(), dto.getPageSize());
            IPage<T> result = baseService.page(page);
            PageResponse<T> pageResponse = PageResponse.of(result);
            return ApiResponse.success(pageResponse);
        } catch (Exception e) {
            log.error("分页查询异常: {}", e.getMessage(), e);
            return ApiResponse.error(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 查询所有实体
     * 
     * @return 实体列表
     */
    @GetMapping("/list")
    @Operation(summary = "查询列表", description = "查询所有实体列表")
    public ApiResponse<List<T>> list() {
        try {
            List<T> list = baseService.list();
            return ApiResponse.success(list);
        } catch (Exception e) {
            log.error("查询列表异常: {}", e.getMessage(), e);
            return ApiResponse.error(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 统计总数
     * 
     * @return 总数
     */
    @GetMapping("/count")
    @Operation(summary = "统计总数", description = "统计实体总数")
    public ApiResponse<Long> count() {
        try {
            long count = baseService.count();
            return ApiResponse.success(count);
        } catch (Exception e) {
            log.error("统计总数异常: {}", e.getMessage(), e);
            return ApiResponse.error(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 将DTO转换为实体对象
     * 子类需要实现此方法
     * 
     * @param dto DTO对象
     * @return 实体对象
     */
    protected abstract T convertToEntity(D dto);
}